#include <iostream>
#include <fstream>

#pragma warning(disable:4099)
#include <gtkmm.h>
#pragma warning(default:4099)

#include <glibmm/timer.h>

//#include <winsock2.h>
#include <netinet/in.h>
#pragma comment(lib, "ws2_32.lib")

#include "Logger.h"
#include "RawImage.h"
#include "MainWindow.h"

namespace RawProject
{
	namespace GUI
	{
		MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade)
			: Gtk::Dialog(cobject),m_refGlade(refGlade),m_dareaImage(0),m_image(),m_imgbuffer(0),m_statusBar(0),m_contextId(0)
		{
		    Gtk::Button * buttonPtr = 0;

			this->m_refGlade->get_widget("button1",buttonPtr);
			if(buttonPtr)
			{
				buttonPtr->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_open_document));
			}
			buttonPtr = 0;

			this->m_refGlade->get_widget("button2",buttonPtr);
			if(buttonPtr)
			{
				buttonPtr->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_close_document));
			}
			buttonPtr = 0;

			Gtk::ImageMenuItem* menuItem = 0;

            // Initializing the "open" menuItem
			this->m_refGlade->get_widget("imagemenuitem2",menuItem);
			if(menuItem)
			{
				menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_open_document));
			}
			menuItem = 0;

            // Initializing the "save" menuItem
			this->m_refGlade->get_widget("imagemenuitem3",menuItem);
			if(menuItem)
			{
				menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_save));
			}
			menuItem = 0;

            // Initializing the "quit" menuItem
			this->m_refGlade->get_widget("imagemenuitem5",menuItem);
			if(menuItem)
			{
				menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_quit));
			}
			menuItem = 0;

			this->m_refGlade->get_widget("drawingarea1",this->m_dareaImage);
			if(this->m_dareaImage)
			{
				this->m_dareaImage->signal_expose_event().connect(sigc::mem_fun(*this, &MainWindow::darea_on_expose_event));
				m_dareaImage->add_events(Gdk::POINTER_MOTION_MASK);
				m_dareaImage->signal_motion_notify_event().connect(sigc::mem_fun(*this,&MainWindow::darea_motion_event));
			}

			this->m_refGlade->get_widget("statusbar1",this->m_statusBar);
			if(this->m_statusBar)
			{
				m_contextId = m_statusBar->get_context_id("Image status");
			}

			this->m_refGlade->get_widget("hscale1",m_scaleSize);
			if(m_scaleSize)
			{
				m_scaleSize->set_sensitive(false);
			}

			this->m_refGlade->get_widget("buttonToneMapping",m_buttonApply);
			if(m_buttonApply)
			{
				m_buttonApply->set_sensitive(false);
				m_buttonApply->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_apply_clicked));
			}

			this->m_refGlade->get_widget("buttonRestore",m_buttonRestore);
			if(m_buttonRestore)
			{
				m_buttonRestore->set_sensitive(false);
				m_buttonRestore->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_restore_clicked));
			}

			this->signal_event().connect(sigc::mem_fun(*this,&MainWindow::on_my_event));

			std::list<Gtk::TargetEntry> targetList;
			targetList.push_back(Gtk::TargetEntry("text/uri-list"));

			this->drag_dest_set(targetList);
			this->signal_drag_data_received().connect(sigc::mem_fun(*this,&MainWindow::on_my_data_received));
		}

		MainWindow::~MainWindow()
		{
		}

        bool MainWindow::LoadImage(Glib::ustring & fileName)
        {
            if(m_image.LoadFromFile(fileName))
            {
                this->m_buttonApply->set_sensitive();
                this->m_scaleSize->set_sensitive();
                this->m_buttonRestore->set_sensitive();

                Gtk::Adjustment adj(1, 1, m_image->get_width() / 4 > m_image->get_height() / 4 ? m_image->get_width() / 4 : m_image->get_height() / 4);
                this->m_scaleSize->set_adjustment(adj);

                m_dareaImage->queue_draw();
                return true;
            }

            m_dareaImage->queue_draw();
            return false;
        }

		void MainWindow::on_open_document()
		{
			Gtk::FileChooserDialog dialog(*this,"Pick a RAW file please...");

			dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
			dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

			int result = dialog.run();

			switch(result)
			{
			case (Gtk::RESPONSE_OK):
				{
					Glib::ustring str = dialog.get_filename();
					RawProject::globalLogger.Log("Button1 clicked. File picked : " + str);

					LoadImage(str);
				}
				break;
			case (Gtk::RESPONSE_CANCEL):
				RawProject::globalLogger.Log("Loading file canceled");
				break;
			}
		}

		void MainWindow::on_close_document()
		{
			if(m_image)
				RawProject::globalLogger.Log("Closing document");

			m_image.clear();
			m_dareaImage->queue_draw();

			this->m_buttonApply->set_sensitive(false);
			this->m_scaleSize->set_sensitive(false);
			this->m_buttonRestore->set_sensitive(false);
		}

        void MainWindow::on_save()
        {
            if(m_image)
            {
                Gtk::FileChooserDialog dialog("Select name and folder for your image",Gtk::FILE_CHOOSER_ACTION_SAVE);
                dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
                dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);

                int result = dialog.run();

                if(result == Gtk::RESPONSE_OK)
                    m_image->save(dialog.get_filename() + ".bmp","bmp");
            }
        }

		void MainWindow::on_quit()
		{
			if(m_imgbuffer)
			{
				delete[] m_imgbuffer;
				m_imgbuffer = 0;
			}
			hide();

			RawProject::globalLogger.Log("Quitting program");
		}

		bool MainWindow::darea_on_expose_event(GdkEventExpose* ev)
		{
			if(m_image)
			{
				int width = m_image->get_width();
				int height = m_image->get_height();

				m_image->render_to_drawable(m_dareaImage->get_window(), m_dareaImage->get_style()->get_black_gc(),
					0, 0, 0, 0, width, height, Gdk::RGB_DITHER_NONE, 0, 0);

				m_dareaImage->set_size_request(width,height);
			}
			else
			{
				m_dareaImage->set_size_request(0,0);
			}

			return true;
		}

		bool MainWindow::darea_motion_event(GdkEventMotion * evt)
		{
			std::ostringstream str;
			m_statusBar->pop(m_contextId);

			unsigned short R=0,G=0,B=0;
			m_image.getPixelValue((int)evt->x, (int)evt->y, R, G, B);

			str << "(" << evt->x << ";" << evt->y << ")" << " => " << "[" << R << ";" << G << ";" << B << "]";
			m_statusBar->push(str.str(), m_contextId);
			return true;
		}

		void MainWindow::on_apply_clicked()
		{
			m_image.applyToneMapping((int)m_scaleSize->get_value());
			m_dareaImage->queue_draw();
		}

		void MainWindow::on_restore_clicked()
		{
		    m_image.restoreImage();
		    m_dareaImage->queue_draw();
		}

		bool MainWindow::on_my_event(GdkEvent * event)
		{
		    return false;
		}

		void MainWindow::on_my_data_received(
            const Glib::RefPtr<Gdk::DragContext>& dcontext, int x, int y,
            const Gtk::SelectionData& selection_data, guint info, guint time)
        {
            Glib::ustring fileName = Glib::filename_from_uri(selection_data.get_data_as_string());
            fileName = fileName.substr(0,fileName.length() - 2); // Remove CRLF

            LoadImage(fileName);

            dcontext->drag_finish(false, false, time);
        }
	}
}
